/**
 *
 * @author John Creecy
 */
package battlebarnapplet;

import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;

import battlebarnapplet.entities.ClientProjectileEntity;
import battlebarnapplet.entities.LocationEntity;
import battlebarnapplet.entities.PlayerMovementEntity;
import battlebarnapplet.util.Util;
import battlebarnserver.util.Constants;

public class Board extends JPanel implements ActionListener {

	private static Board instance = null;
	private Timer timer;
	private Player player;
	private Image playerFacing1;
	private Image playerFacing2;
	private Image playerFacing3;
	private Image playerFacing4;
	private Image projectileImage;
	private Image critter;
	private Image bgImage;
	private Image inanimateImage;
	private Iterator it;
	private Long lastShot;
	private Long lastMove;
	private Long currentTime;
	public byte[] sendData;
	public static boolean hostPlayer;
	public static String playerIp;
	public static Font defaultFont;
	public static Font headingFont;
	public static Long lastPacketTime;
	public static String winnerName;
	public static int lastDirection;
	
	// Player locations
	public static ConcurrentHashMap<String, LocationEntity> playerLocs = new ConcurrentHashMap<String, LocationEntity>();
	// AI locations
	public static ConcurrentHashMap<String, LocationEntity> enemyLocs = new ConcurrentHashMap<String, LocationEntity>();
	// Newly pawned projectiles
	public static ConcurrentHashMap<String, ClientProjectileEntity> projectiles = new ConcurrentHashMap<String, ClientProjectileEntity>();
	// Active projectile tracking
	public static Vector<ClientProjectileEntity> projectileLocs = new Vector<ClientProjectileEntity>();
	// Projectiles scheduled for removal on next client movement cycle
	public static Vector<String> removeProjectiles = new Vector<String>();
	// Inanimate object locations
	public static Vector<LocationEntity> inanimateLocs = new Vector<LocationEntity>();

	public Board() {
		Util util = new Util();
		playerIp = (util.getPrimaryInterface());
		winnerName = "";
		lastShot = 0L;
		lastMove = 0L;
		sendDirection();
		addKeyListener(new TAdapter());
		setFocusable(true);
		setDoubleBuffered(true);
		player = new Player();
		playerFacing1 = (new ImageIcon(this.getClass().getResource("assets/sprites/car1.gif"))).getImage();
		playerFacing2 = (new ImageIcon(this.getClass().getResource("assets/sprites/car2.gif"))).getImage();
		playerFacing3 = (new ImageIcon(this.getClass().getResource("assets/sprites/car3.gif"))).getImage();
		playerFacing4 = (new ImageIcon(this.getClass().getResource("assets/sprites/car4.gif"))).getImage();
		projectileImage = (new ImageIcon(this.getClass().getResource("assets/sprites/shot.png"))).getImage();
		critter = (new ImageIcon(this.getClass().getResource("assets/sprites/goat.gif"))).getImage();
		bgImage = (new ImageIcon(this.getClass().getResource("assets/tiles/TileCanvas.png"))).getImage();
		inanimateImage = (new ImageIcon(this.getClass().getResource("assets/tiles/Rock.png"))).getImage();
		
		defaultFont = new Font("Arial",Font.BOLD,15);
		headingFont = new Font("Arial",Font.BOLD,20);
		timer = new Timer(50, this);
		timer.start();
	}

	public static Board getInstance() {
		if (instance == null) {
			instance = new Board();
		}
		return instance;
	}

	@Override
	public void paint(Graphics g) {
		super.paint(g);
		Animations movements = new Animations();
		movements.moveProjectiles();
		DrawGraphics.drawBackground(g, bgImage);
	
		// draw inanimates
		for (int i = 0; i < Board.inanimateLocs.size(); i++) {
			LocationEntity locationEntity = Board.inanimateLocs.get(i);
			DrawGraphics.drawSprite(g,locationEntity.getX(), locationEntity.getY(), inanimateImage);
		}

		// draw projectiles
		for (int i = 0; i < Board.projectileLocs.size(); i++) {
			ClientProjectileEntity locationEntity = Board.projectileLocs.get(i);
			DrawGraphics.drawSprite(g,locationEntity.getPixelX(), locationEntity.getPixelY(), projectileImage);
		}

		// draw players
		if (playerLocs.isEmpty()) {
			Player.direction = 2;
			sendDirection();
			Player.direction = 0;
		} else {
			it = playerLocs.entrySet().iterator();
			while (it.hasNext()) {
				Map.Entry mapEntry = (Map.Entry) it.next();
				LocationEntity locationEntity = (LocationEntity) mapEntry.getValue();
				switch (locationEntity.getFacing()) {
				case 1:
					DrawGraphics.drawSprite(g,locationEntity.getX(), locationEntity.getY(), playerFacing1);
					break;
				case 2:
					DrawGraphics.drawSprite(g,locationEntity.getX(), locationEntity.getY(), playerFacing2);
					break;
				case 3:
					DrawGraphics.drawSprite(g,locationEntity.getX(), locationEntity.getY(), playerFacing3);
					break;
				case 4:
					DrawGraphics.drawSprite(g,locationEntity.getX(), locationEntity.getY(), playerFacing4);
					break;
				default:
					DrawGraphics.drawSprite(g,locationEntity.getX(), locationEntity.getY(), playerFacing2);
					break;
				}
				currentTime = (long) (System.currentTimeMillis());
				DrawGraphics.drawHealthBars(g, locationEntity.getX(), locationEntity.getY(), Constants.STARTING_PLAYER_HEALTH, locationEntity.getHealth());
				DrawGraphics.drawLabels(g, locationEntity.getX(), locationEntity.getY(), locationEntity.getPlayerId().trim());
				//DrawGraphics.drawMoveCooldownBar(g, locationEntity.getX(), locationEntity.getY(), Constants.CLIENT_MOVE_THROTTLE_MILLISECONDS, (currentTime - lastMove));
				if(playerIp.equals(locationEntity.getPlayerId().trim()) || (hostPlayer == true && locationEntity.getPlayerId().trim().equals(Constants.CLIENT_LOOP_BACK_ADDRESS))) {
					DrawGraphics.drawCooldownBar(g, locationEntity.getX(), locationEntity.getY(), Constants.CLIENT_SHOT_THROTTLE_MILLISECONDS, (currentTime - lastShot));	
				}
			}
		}

		// draw critters
		it = enemyLocs.entrySet().iterator();
		while (it.hasNext()) {
			Map.Entry mapEntry = (Map.Entry) it.next();
			LocationEntity locationEntity = (LocationEntity) mapEntry.getValue();
			DrawGraphics.drawSprite(g,locationEntity.getX(), locationEntity.getY(), critter);
			DrawGraphics.drawHealthBars(g, locationEntity.getX(), locationEntity.getY(), Constants.STARTING_CRITTER_HEALTH, locationEntity.getHealth());
			DrawGraphics.drawLabels(g, locationEntity.getX(), locationEntity.getY(), "Critter");
		}
	
		// winner test
		if(winnerName.length() >= 1) {
			DrawGraphics.displayWinner(g);
		}

		Toolkit.getDefaultToolkit().sync();
		g.dispose();
	}

	public void actionPerformed(ActionEvent e) {
		repaint();
		if (Player.direction > 0) {
			sendDirection();
		}
		if (Player.shot == 1) {
			sendShot();
		}
	}

	private void sendDirection() {
		currentTime = (long) (System.currentTimeMillis());
		if ((currentTime - lastMove) > Constants.CLIENT_MOVE_THROTTLE_MILLISECONDS) {
			try {
				DatagramSocket clientSocket = new DatagramSocket();
				InetAddress IPAddress = InetAddress.getByName(ClientStart.targetIp.getText());
				sendData = new byte[1024];
				sendData = Integer.toString(Player.direction).getBytes();
				DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, ClientStart.serverPort);
				clientSocket.send(sendPacket);
				clientSocket.close();
				lastDirection = Player.direction;
				lastMove = currentTime;
			} catch (IOException ex) {
				Logger.getLogger(Board.class.getName()).log(Level.SEVERE, null, ex);
			}
		}
	}

	private void sendShot() {
		currentTime = (long) (System.currentTimeMillis());
		if ((currentTime - lastShot) > Constants.CLIENT_SHOT_THROTTLE_MILLISECONDS) {
			try {
				DatagramSocket clientSocket = new DatagramSocket();
				InetAddress IPAddress = InetAddress.getByName(ClientStart.targetIp.getText());
				sendData = new byte[1024];
				sendData = Integer.toString(5).getBytes();
				DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, ClientStart.serverPort);
				clientSocket.send(sendPacket);
				clientSocket.close();
				lastShot = currentTime;
			} catch (IOException ex) {
				Logger.getLogger(Board.class.getName()).log(Level.SEVERE, null, ex);
			}
		}
	}

	private class TAdapter extends KeyAdapter {

		public void keyReleased(KeyEvent e) {
			player.keyReleased(e);
		}

		public void keyPressed(KeyEvent e) {
			player.keyPressed(e);
		}
	}
}
